home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Hooks.cp
-
- Contains: Hooking into the Mac OS by intercepting traps
-
- A "hook" consists of a short machine-language sequence that calls
- our trap monitoring routine, and then passes control onto the ROM routine
- This sequence must be placed in the system heap so that it is guaranteed
- to be close enough to the trap dispatch table.
-
- Between the time that we first install this hook and the time that we
- are ready to remove it, the application may have installed a hook of its
- own! If it has, we can't just remove our hook by restoring the old
- trap handler. Instead we disable the hook by having it jump directly
- to the original routine.
-
- Written by: Jack Palevich, [Original idea and C implementation by Jay Fenton]
-
- Copyright: © 1989 by Apple Computer, Inc., all rights reserved.
-
- Change History:
-
- 10/15/89 JHP objectified today
-
- To Do:
- */
-
- #ifndef __OSUTILS__
- #include <OSUtils.h>
- #endif
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
- #ifndef __SYSEQU__
- #include <SysEqu.h>
- #endif
-
- #ifndef __HOOKS__
- #include "Hooks.h"
- #endif
-
- /* At the point we do the move.l sp,-(sp) this is the state of the stack
-
- offset size what's there
- ====== ==== =======================
- 0 2 trap number
- 2 4 d0
- 6 4 d1
- 10 4 d2
- 14 4 d3
- 18 4 d4
- 22 4 d5
- 26 4 d6
- 30 4 d7
- 34 4 a0
- 38 4 a1
- 42 4 a2
- 46 4 a3
- 50 4 a4
- 54 4 a5
- 58 4 return address
- 62 ? last argument to trap
- 62+? ? second to last argument to trap
- */
-
- struct hookentry {
- long movemON; // movem.l d0-d7/a0-a5,-(sp)
-
- short moveiw; // movei.w #,-sp
- short tNumber;
-
- short pushsp; // move.l sp,-(sp)
-
- short moveil; // movei.l #,-sp
- void* userRefNum;
-
- short JSR;
- pascal void (*subroutine)(short, THookStackFrame*, void*);
-
- long movemOFF; // movem.l (sp)+,d0-d7/a0-a5
-
- short JMP; // jmp.l #
- long OldTrapAddr;
- };
-
- struct patch {
- short JMP;
- long OldTrapAddr;
- };
- typedef patch *patchptr;
-
- THooks::THooks(short numTraps, const short* trapList,
- pascal void (*trapHandler)(short, THookStackFrame*, void* userRefNum), void* userRefNum)
- {
- // Allocate fHooks in the system heap
-
- fHooks = (hookentry*) NewPtrSys( sizeof( hookentry) * numTraps);
-
- if ( ! fHooks ) return;
-
- fNumHooks = numTraps;
-
-
- for ( short i = 0; i < numTraps; i++ )
- {
- hookentry* hooker = & fHooks[i];
- short whatTrap = trapList[i];
- TrapType trapType;
- short trapNum;
- TrapToTypeAndNum(whatTrap, trapType, trapNum);
- hooker->movemON = 0x48E7FFFc; // movem.l d0-d7/a0-a5,-(sp)
- hooker->moveiw = 0x3F3C; // movei.w #,-(sp)
- hooker->tNumber = whatTrap; // a code number
- hooker->pushsp = 0x2F0F; // move.l sp,-(sp)
- hooker->moveil = 0x2F3C; // movei.l #,-(sp)
- hooker->userRefNum = userRefNum;
- hooker->JSR = 0x4EB9; // JSR abs.l
- hooker->subroutine = trapHandler;
- hooker->movemOFF = 0x4CDF3FFF; // movem.l (sp)+,d0-d7/a0-a5
- hooker->JMP = 0x4EF9; // JMP abs.l
- hooker->OldTrapAddr = NGetTrapAddress(trapNum, trapType);
- NSetTrapAddress((long) hooker, trapNum, trapType);
- } // for i
- }
-
-
- THooks::~THooks()
- {
- if ( ! fHooks ) return; // Never allocated
-
- register short i;
- // first check to verify that none of the traps have been
- // overriden by someone else:
-
- Boolean clean = true;
-
- for (i = 0; i < fNumHooks; i++)
- {
- TrapType trapType;
- short trapNum;
- TrapToTypeAndNum(fHooks[i].tNumber, trapType, trapNum);
- if ( ((long) NGetTrapAddress(trapNum, trapType) ) !=
- fHooks[i].OldTrapAddr)
- {
- clean = false;
- break;
- }
- }
-
- if ( clean )
- {
- // Yay! Nobody's patched after us, so we can unpatch ourselves
-
- for (i = 0; i < fNumHooks; i++)
- {
- TrapType trapType;
- short trapNum;
- TrapToTypeAndNum(fHooks[i].tNumber, trapType, trapNum);
- NSetTrapAddress(fHooks[i].OldTrapAddr, trapNum, trapType);
- }
- // and we can delete our hook array
-
- THz oldZone = (*(THz*) TheZone);
- SetZone((*(THz*) SysZone));
- DisposPtr((Ptr) fHooks);
- SetZone(oldZone);
-
- fHooks = 0;
- }
- else
- {
- // we can not completely extract our patch area, so we leave it in place, but we
- // short-circuit the patch
-
- for (i = 0; i < fNumHooks; i++)
- { /* point at our jump instruction leading out */
- hookentry* h = & fHooks[i];
- patchptr thispatch = (patchptr) h;
- thispatch->JMP = 0x4EF9;
- thispatch->OldTrapAddr = h->OldTrapAddr;
- }
- }
- }
-